﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
using System.ServiceModel;
using System.Text;
using System.Text.RegularExpressions;
using Elderos.AI;
using Elderos.Highlight;
using Elderos.Highlight.Search;
using Elderos.Ontology;
using Elderos.Utils;
using Encog.Neural.Networks;

namespace WebHighlighterService
{
    [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.Single)]
    public class WebHighlighterService : IWebHighlighterService
    {
        private readonly IHighlighter _highlighter;
        private readonly IOntologyData _ontology;

        private readonly Regex _tagRx = new Regex("<[^>]+?>", RegexOptions.Compiled);

        public WebHighlighterService()
        {
            var ontologyString = ConfigurationManager.ConnectionStrings["Ontology"].ConnectionString;
            var ontology = new OntologyData(ontologyString);
            ontology.Initialize();
            _ontology = ontology;

            IAmbiguityResolver ambiguityResolver = null;
            int networkID;
            if (int.TryParse(ConfigurationManager.AppSettings["networkID"], out networkID))
            {
                double threshold;
                INormalizer normalizer;
                BasicNetwork network = LoadNetworkFromDB(networkID, _ontology, out threshold, out normalizer);
                ambiguityResolver = new NeuralAmbiguityResolver(threshold, network, normalizer);
                //new SimpleAmbiguityResolver(0.5);
            }
            if (ambiguityResolver == null)
                ambiguityResolver = new SimpleAmbiguityResolver(0);

            _highlighter = new Highlighter(
                new[]{new RabinKarpSearcher(ontology)},
                new SearchResultAdapter(),
                new RuleRanker(_ontology),
                ambiguityResolver,
                _ontology
                );
        }

        private static BasicNetwork LoadNetworkFromDB(int networkID, IOntologyData ontology, out double threshold, out INormalizer normalizer)
        {
            Network serialized = ontology.GetNetwork(networkID);

            threshold = serialized.Threshold;

            var serializer = new BinaryFormatter();
            using(var ms = new MemoryStream())
            {
                ms.Write(serialized.NormalizerData, 0, serialized.NormalizerData.Length);
                ms.Position = 0;

                normalizer = (Normalizer) serializer.Deserialize(ms);
            }

            using (var ms = new MemoryStream())
            {
                ms.Write(serialized.NetworkData, 0, serialized.NetworkData.Length);
                ms.Position = 0;

                var network = (BasicNetwork)serializer.Deserialize(ms);
                return network;
            }
        }

        public List<EntityInfo> Highlight(Stream stream)
        {
            string html = new StreamReader(stream).ReadToEnd();
            var articleHighlight = _highlighter.Highlight(html);

            var result = new List<EntityInfo>();

            var tagIntervals = _tagRx.Matches(html)
                .Cast<Match>()
                .Select(x => new Interval<int>(x.Index, x.Index + x.Length - 1))
                .ToArray();

            foreach (var position in articleHighlight.Positions)
            {
                if (position.Winner == null) continue;

                if (position.CharInterval.IsIntersection(tagIntervals)) continue;

                var info = new EntityInfo();

                int entityID = position.Winner.EntityID;
                var entity = _ontology.GetEntityAsync(entityID).Result;
                info.Start = position.CharInterval.First;
                info.Length = position.CharInterval.Length;
                info.MID = entity.MID.Trim();

                result.Add(info);
            }

            return result;
        }
    }
}
